import hashlib
import time
import requests
from typing import Dict, Optional
import asyncio
import aiomysql
from datetime import datetime

class EventCompanyClient:
    """
    赛事公司HTTP接口客户端
    
    功能：
    1. 处理登录认证
    2. 自动生成请求签名
    3. 提供基础API调用方法
    """
    
    def __init__(self, base_url: str, username: str, pwd: str):
        """
        初始化客户端
        
        :param base_url: 接口基础地址
        :param app_id: 应用ID
        :param app_secret: 应用密钥
        """
        self.base_url = base_url
        self.username = username
        self.pwd = pwd
        self.access_token: Optional[str] = None
        self._cache = {}  # 选手点位缓存字典
    
    async def _login(self):
        """
        登录获取token
        """
        login_params = {
            'username': self.username,
            'password': self.pwd
        }
        
        # 使用JSON格式发送登录请求
        headers = {'Content-Type': 'application/json'}
        login_url = f"{self.base_url}/prod-api/login"
        
        try:
            response = requests.post(login_url, json=login_params, headers=headers)
            response.raise_for_status()
            
            login_data = response.json()
            self.access_token = login_data['token']
                
        except requests.exceptions.RequestException as e:
            raise Exception(f"登录失败: {str(e)}")


    
            
    async def login_example(self):
        """
        登录调用示例
        
        示例用法:
        client = EventCompanyClient(base_url="https://api.example.com", 
                                  username="your_username", 
                                  pwd="your_password")
        try:
            await client._login()
            print(f"登录成功，token: {client.access_token}")
        except Exception as e:
            print(f"登录失败: {e}")
        """
        try:
            await self._login()
            print(f"登录成功，token: {self.access_token}")
            return True
        except Exception as e:
            print(f"登录失败: {e}")
            return False
            
    async def get_results_by_positions(self, id: int, bib: str, pos: list):
        """
        根据位置获取结果
        
        :param id: 比赛ID
        :param bib: 选手号码
        :param pos: 位置列表
        :return: 接口返回的JSON数据
        """
        if not self.access_token:
            await self._login()
            
        url = f"{self.base_url}/prod-api/tp-api/results"
        headers = {
            'Content-Type': 'application/json',
            'Authorization': f'Bearer {self.access_token}'
        }

        body = {
            "id": id,
            "bib": bib,
            "pos": pos
        }
        
        try:
            print(f"发送请求: {body}")
            response = requests.post(url, json=body, headers=headers)
            response.raise_for_status()
            result = response.json()
            if result.get('code') == 200 and result.get('data'):
                await self._save_to_database(result['data'], pos[0])
            return result
        except requests.exceptions.RequestException as e:
            raise Exception(f"获取结果失败: {str(e)}")
            
    async def _save_to_database(self, players_data: list, point_type: int):
        """
        将选手数据保存到数据库
        
        :param players_data: 选手数据列表
        :param point_type: 点位类型
        """
        from datetime import datetime
        from Main import pool, create_db_pool
        
        # 点位类型映射关系
        point_mapping = {
            0: 0,
            1: 5,
            2: 10,
            6: 15,
            8: 20,
            99: 42
        }
        
        # 转换点位类型
        mapped_point_type = point_mapping.get(point_type, point_type)
        
        batch_data = []
        print(f"获取到的插入的数据: {players_data}")
        for player in players_data:
            if not player.get('gunTime') or not player.get(f'point{point_type}Time'):
                continue
                
            # 计算时间差
            gun_time = datetime.strptime(player['gunTime'], '%Y-%m-%d %H:%M:%S.%f')
            point_time = datetime.strptime(player[f'point{point_type}Time'], '%Y-%m-%d %H:%M:%S.%f')
            delta = point_time - gun_time
            hours, remainder = divmod(delta.seconds, 3600)
            minutes, seconds = divmod(remainder, 60)
            formatted_time = f"{hours:02d}:{minutes:02d}:{seconds:02d}"
            
            # 检查缓存
            player_id = player.get('playerNo', '-')
            cache_key = f"{player_id}_{point_type}"
            
            if cache_key in self._cache:
                continue  # 已处理过，跳过
                
            # 构建插入数据
            batch_data.append((
                player_id,  # id
                player.get('name', ''),  # name
                player.get('nationality', ''),  # country
                player.get('gender', ''),  # gender
                mapped_point_type,  # 使用映射后的点位类型
                formatted_time  # time
            ))
            
            # 更新缓存
            self._cache[cache_key] = True
            
        print(f"准备插入的数据: {batch_data}")
        
        if not batch_data:
            return {"status": "success", "inserted": 0}
            
        try:
            async with pool.acquire() as conn:
                async with conn.cursor(aiomysql.DictCursor) as cur:
                    # 直接插入，因为缓存已经确保不重复
                    await cur.executemany(
                        "INSERT INTO curPassResult (id, name, country, gender, type, time, timestamp) VALUES (%s, %s, %s, %s, %s, %s, NOW())",
                        batch_data
                    )
                    print(f"插入数据: {batch_data}")
                    await conn.commit()
                    print("数据插入成功")  # 调试信息，可删除
                    return {"status": "success", "inserted": len(batch_data)}

        except aiomysql.OperationalError:
            await create_db_pool()
            return {"status": "error", "message": "Database connection error"}
        except Exception as e:
            await conn.rollback()
            return {"status": "error", "message": str(e)}
            
    async def process_results_data(self, result_data: dict) -> list:
        """
        处理接口返回的选手数据
        
        :param result_data: 接口返回的选手数据
        :return: 格式化后的点位用时列表
        """
        if not result_data.get('data'):
            return []
            
        from datetime import datetime
        
        try:
            formatted_results = []
            for player in result_data['data']:
                if not player.get('gunTime'):
                    continue
                    
                base_time = datetime.strptime(player['gunTime'], '%Y-%m-%d %H:%M:%S.%f')
                
                # 计算各点位时间差
                point_times = {}
                for key, value in player.items():
                    if key.endswith('Time') and value:
                        point_time = datetime.strptime(value, '%Y-%m-%d %H:%M:%S.%f')
                        delta = point_time - base_time
                        hours, remainder = divmod(delta.seconds, 3600)
                        minutes, seconds = divmod(remainder, 60)
                        point_times[key] = f"{hours:02d}:{minutes:02d}:{seconds:02d}"
                
                formatted_results.append({
                    'name': player.get('name', ''),
                    'gender': player.get('gender', ''),
                    'nationality': player.get('nationality', ''),
                    'state': player.get('state', ''),
                    'point_times': point_times
                })
                
            return formatted_results
        except Exception as e:
            print(f"处理选手数据出错: {e}")
            return []
            
    async def get_players(self, id: int):
        """
        获取选手列表
        
        :param id: 比赛ID
        :return: 接口返回的JSON数据
        """
        if not self.access_token:
            await self._login()
            
        url = f"{self.base_url}/prod-api/tp-api/players"
        headers = {
            'Authorization': f'Bearer {self.access_token}'
        }
        
        params = {
            "id": id
        }
        
        try:
            response = requests.get(url, headers=headers, params=params)
            response.raise_for_status()
            result = response.json()
            
            # 构建batch_data数据
            batch_data = [
                (
                    player['bib'],  # id
                    player['name'],  # name
                    player['nationality'],  # country
                    player['gender']  # gender
                )
                for player in result.get('data', [])
            ]
            
            from datetime import datetime
            from Main import pool, create_db_pool
            try:
                async with pool.acquire() as conn:
                    async with conn.cursor(aiomysql.DictCursor) as cur:
                        # 直接插入，因为缓存已经确保不重复
                        await cur.executemany(
                            "INSERT INTO curPlayerList (id, name, country, gender) VALUES (%s, %s, %s, %s)",
                            batch_data
                        )
                        print(f"插入数据: {batch_data}")
                        await conn.commit()
                        print("数据插入成功")  # 调试信息，可删除
                        return {"status": "success", "inserted": len(batch_data)}
            except aiomysql.OperationalError:
                await create_db_pool()
                return {"status": "error", "message": "Database connection error"}
            except Exception as e:
                await conn.rollback()
                return {"status": "error", "message": str(e)}
            return result
        except requests.exceptions.RequestException as e:
            raise Exception(f"获取选手列表失败: {str(e)}")
            
    async def calculate_split_times(self, result_data: dict) -> list:
        """
        计算选手各点位的通过用时
        
        :param result_data: 接口返回的选手数据
        :return: 格式化后的点位用时列表
        """
        if not result_data.get('data') or not result_data['data'][0].get('point0Time'):
            return []
            
        base_time = result_data['data'][0]['point0Time']
        
        # 定义点位映射关系
        point_mapping = {
            'point0Time': 0,
            'point1Time': 5,
            'point2Time': 10,
            'point3Time': 15,
            'point4Time': 20,
            'point99Time': 42
        }
        
        from datetime import datetime
        
        try:
            base_datetime = datetime.strptime(base_time, '%Y-%m-%d %H:%M:%S.%f')
            
            # 使用列表推导式生成结果
            return [
                {
                    "type": str(name),
                    "time": (
                        '00:00:00' if point == 'point0Time' else
                        self._calculate_time_diff(base_datetime, result_data['data'][0][point]) 
                        if point in result_data['data'][0] and result_data['data'][0][point] 
                        else '--:--:--'
                    )
                }
                for point, name in point_mapping.items()
            ]
                    
        except Exception as e:
            print(f"计算点位用时出错: {e}")
            return []
            
    def _calculate_time_diff(self, base_datetime, point_time_str):
        """
        计算时间差并格式化为HH:MM:SS
        
        :param base_datetime: 基准时间
        :param point_time_str: 点位时间字符串
        :return: 格式化后的时间差
        """
        point_datetime = datetime.strptime(point_time_str, '%Y-%m-%d %H:%M:%S.%f')
        delta = point_datetime - base_datetime
        hours, remainder = divmod(delta.seconds, 3600)
        minutes, seconds = divmod(remainder, 60)
        return f"{hours:02d}:{minutes:02d}:{seconds:02d}"
    
async def main():
    client = EventCompanyClient(base_url="http://cluster.rts.thinkgo-iot.cc", 
                              username="kd", 
                              pwd="123456")
    try:
        await client._login()
        print(f"登录成功，token: {client.access_token}")
        ret = await client.get_results_by_positions(id=1, bib="", pos=[1])
        print(f"获取结果: {ret}")
        ret = await client.get_players(id=1)
        print(f"获取选手列表: {ret}")
    except Exception as e:
        print(f"登录失败: {e}")

if __name__ == "__main__":
    import asyncio
    asyncio.run(main())

